﻿using UnityEngine;
using System.Collections;
using System.Diagnostics;
using System.Collections.Generic;
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace Net
{
    public partial class AsycUdpClient
    {
        public static class DebugInfo
        {
            public static bool Data = false;
        }

        static readonly byte pingByte = byte.MaxValue;
        Stopwatch pingWatch;

        bool Pinging
        {
            get
            {
                return pingWatch != null;
            }
        }

        private static int upByteBuffer;
        private static int downByteBuffer;
        private static int upByteTotal;
        private static int downByteTotal;
        
        public static int UpBytes
        {
            get
            {
                int n = upByteBuffer;
                upByteBuffer = 0;

                return n;
            }
        }

        public static int DownBytes
        {
            get
            {
                int n = downByteBuffer;
                downByteBuffer = 0;

                return n;
            }
        }

        public static int UpBytesTotal
        {
            get
            {
                return upByteTotal;
            }
        }

        public static int DownBytesTotal
        {
            get
            {
                return downByteTotal;
            }
        }
        
        int myID;

        List<string> debugMessageList = new List<string>();
        void Debug(string s) { debugMessageList.Add(s); }
        List<MessageBuffer> inMessages = new List<MessageBuffer>(), outMessages = new List<MessageBuffer>();

        private TcpClient tcpSocket;
        private IPEndPoint tcpAdress;
        
        private UdpClient udpSocket;
        private IPEndPoint udpAdress;

        private Thread receiveThread;
        private Thread sendThread;
        private Thread aliveThread;

        public bool Connected
        {
            get
            {
                if (tcpSocket == null) return false;
                return tcpSocket.Connected;
            }
        }

        public AsycUdpClient()
        {
        }

        

        public void Update()
        {
            while (inMessages.Count > 0)
            {
                while (inMessages[0] == null) ;

                OnMessage(inMessages[0]);
                inMessages.RemoveAt(0);
            }

            string[] debug = debugMessageList.ToArray();
            foreach (string s in debug) if (OnDebug != null) OnDebug(s);
            debugMessageList.Clear();
        }

        

        

        public void Disconnect()
        {
            if (tcpSocket == null || udpSocket == null) return;

            if (tcpSocket.Connected) tcpSocket.GetStream().Close();
            tcpSocket.Close();
            udpSocket.Close();

            tcpSocket = null;
            udpSocket = null;

            OnDisconnect();
            receiveThread.Abort();
            sendThread.Abort();
            aliveThread.Abort();
        }



        void CatchException(Exception e)
        {
            if (OnException != null) OnException(e);
        }

        public void Ping()
        {
            if (!Pinging)
            {
                pingWatch = Stopwatch.StartNew();
                udpSocket.Send(new byte[] { pingByte }, 1);
            }
        }

        public static long Ping(IPEndPoint ip)
        {
            UdpClient client = new UdpClient();

            client.Connect(ip);

            Stopwatch watch = Stopwatch.StartNew();

            client.Send(new byte[] { pingByte }, 1);
            var data = client.Receive(ref ip);

            long millis = watch.Elapsed.Milliseconds;
            watch.Stop();

            client.Close();

            return millis;
        }
    }
}

